﻿#region Using Statements
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using starLiGHT;
using System.Runtime.InteropServices;
using System.Diagnostics;

#endregion

#region COPYRIGHT

/*
    Copyright (c) 2008, 2009, 2010 
        Roland Rosenkranz (Glatzemann@email.de)
*/

#endregion

#region LICENSE

/*
    This file is part of starLiGHT.Collision.

    starLiGHT.Collision is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    starLiGHT.Collision is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with starLiGHT.Collision.  If not, see <http://www.gnu.org/licenses/>.

    
    ADDITIONAL (commercial) LICENSES for starLiGHT.Collision are available on request.
*/

#endregion

#region Box2D Copyright
/*
* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty.  In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#endregion

#region Version Stuff
// **************[ starLiGHT.Engine SVN ]**********************
// * $Rev:: 1486                  $:  Revision of last commit *
// * $Author:: glatzemann         $:  Author of last commit   *
// * $Date:: 2010-10-08 15:55:47 #$:  Date of last commit     *
// ************************************************************

// **************[ Box2D-Repository Info ]*********************
// Header-File: http://code.google.com/p/box2d/source/browse/trunk/Box2D/Box2D/Collision/b2Collision.h
// Revision   : r112
// Change-Date: 2010-06-17
//
// Source-File: http://code.google.com/p/box2d/source/browse/trunk/Box2D/Box2D/Collision/b2Collision.cpp
// Revision   : r112
// Change-Date: 2010-06-17
//
// Status     : Finished!
#endregion

namespace starLiGHT.Physic.TwoD
{
    /// <summary> 
    /// The features that intersect to form the contact point. 
    /// This must be 4 bytes or less.
    /// </summary> 
    public struct ContactFeature
    {
        public enum Type : byte { VERTEX = 0, FACE = 1, };

        /// <summary> 
        /// Feature index on shapeA
        /// </summary> 
        public Byte indexA;

        /// <summary> 
        /// Feature index on shapeB
        /// </summary> 
        public Byte indexB;

        /// <summary> 
        /// The feature type on shapeA
        /// </summary> 
        public Type typeA;

        /// <summary> 
        /// The feature type on shapeB
        /// </summary> 
        public Type typeB;
    } 
 
    /// <summary>Contact ids to facilitate warm starting.</summary>
    [StructLayout(LayoutKind.Explicit)]
    public struct ContactID
    {
        [FieldOffset(0)]
        public ContactFeature cf;
        
        [FieldOffset(0)]
        public UInt32 key;				/// Used to quickly compare contact ids.
    };

    /// <summary>A manifold point is a contact point belonging to a contact
    /// manifold. It holds details related to the geometry and dynamics
    /// of the contact points.<br/><br/>
    /// The local point usage depends on the manifold type:<br/>
    /// -e_circles: the local center of circleB<br/>
    /// -e_faceA: the local center of cirlceB or the clip point of polygonB<br/>
    /// -e_faceB: the clip point of polygonA<br/>
    /// <br/>
    /// This structure is stored across time steps, so we keep it small.<br/>
    /// <remarks>the impulses are used for internal caching and may not provide reliable contact forces, especially for high speed collisions.</remarks>
    public struct ManifoldPoint
    {
        public Vector2 localPoint;		    /// usage depends on manifold type
        public float normalImpulse;	        /// the non-penetration impulse
        public float tangentImpulse;	    /// the friction impulse
        public ContactID id;			    /// uniquely identifies a contact point between two shapes
        public bool isNew;

        public ManifoldPoint Clone()
        {
            ManifoldPoint newPoint = new ManifoldPoint();
            newPoint.localPoint = this.localPoint;
            newPoint.normalImpulse = this.normalImpulse;
            newPoint.tangentImpulse = this.tangentImpulse;
            newPoint.id = this.id;
            return newPoint;
        }
    };

    public enum ManifoldType
    {
        e_circles,
        e_faceA,
        e_faceB
    };

    /// <summary>A manifold for two touching convex shapes.<br/>
    /// Box2D supports multiple types of contact:<br/><br/>
    /// - clip point versus plane with radius<br/>
    /// - point versus point with radius (circles)<br/>
    /// <br/>
    /// The local point usage depends on the manifold type:<br/>
    /// -e_circles: the local center of circleA<br/>
    /// -e_faceA: the center of faceA<br/>
    /// -e_faceB: the center of faceB<br/>
    /// <br/>
    /// Similarly the local normal usage:<br/>
    /// -e_circles: not used<br/>
    /// -e_faceA: the normal on polygonA<br/>
    /// -e_faceB: the normal on polygonB<br/>
    /// <br/>
    /// We store contacts in this way so that position correction can
    /// account for movement, which is critical for continuous physics.
    /// All contact scenarios must be expressed in one of these types.
    /// This structure is stored across time steps, so we keep it small.
    /// </summary>
    public class Manifold
    {
        public ManifoldPoint[] points = new ManifoldPoint[PhysicSettings.MaxManifoldPoints];	/// the points of contact
	    public Vector2 localNormal;						                    /// not use for Type::e_points
	    public Vector2 localPoint;							                /// usage depends on manifold type
	    public ManifoldType type;
	    public int pointCount;								                /// the number of manifold points
    };

    /// <summary>This is used to compute the current state of a contact manifold.</summary>
    public class WorldManifold
    {
	    /// <summary>Evaluate the manifold with supplied transforms. This assumes
	    /// modest motion from the original state. This does not change the
	    /// point count, impulses, etc. The radii must come from the shapes
        /// that generated the manifold.</summary>
	    public void Initialize(Manifold manifold,
					           Transform xfA, float radiusA,
                               Transform xfB, float radiusB)
        {
	        if (manifold.pointCount == 0)
	        {
		        return;
	        }

	        switch (manifold.type)
	        {
	            case ManifoldType.e_circles:
		            {
                        normal.X = 1.0f; normal.Y = 0.0f;
#if !OPTIMIZE
                        Vector2 pointA = Math.Mul(xfA, manifold.localPoint);
			            Vector2 pointB = Math.Mul(xfB, manifold.points[0].localPoint);

                        if (Vector2.DistanceSquared(pointA, pointB) > PhysicSettings.FLT_EPSILON_SQUARED)
			            {
				            normal = pointB - pointA;
				            normal.Normalize();
			            }

			            Vector2 cA = pointA + radiusA * normal;
			            Vector2 cB = pointB - radiusB * normal;
			            points[0] = 0.5f * (cA + cB);
#else
                        Vector2 pointA;
                        Vector2 t; t.X = xfA.R.col1.X * manifold.localPoint.X + xfA.R.col2.X * manifold.localPoint.Y; t.Y = xfA.R.col1.Y * manifold.localPoint.X + xfA.R.col2.Y * manifold.localPoint.Y;
                        pointA.X = xfA.position.X + t.X;
                        pointA.Y = xfA.position.Y + t.Y;

                        Vector2 pointB;
                        Vector2 mp0 = manifold.points[0].localPoint;
                        t.X = xfB.R.col1.X * mp0.X + xfB.R.col2.X * mp0.Y; t.Y = xfB.R.col1.Y * mp0.X + xfB.R.col2.Y * mp0.Y;
                        pointB.X = xfB.position.X + t.X;
                        pointB.Y = xfB.position.Y + t.Y;

                        float tf2 = pointA.X - pointB.X;
                        float tf1 = pointA.Y - pointB.Y;
                        float tf3 = tf2 * tf2 + tf1 * tf1;
                        if (tf3 > PhysicSettings.FLT_EPSILON_SQUARED)
                        {
                            normal.X = pointB.X - pointA.X;
                            normal.Y = pointB.Y - pointA.Y;
                            normal.Normalize();
                        }

                        Vector2 cA; cA.X = pointA.X + radiusA * normal.X; cA.Y = pointA.Y + radiusA * normal.Y;
                        Vector2 cB; cB.X = pointB.X - radiusB * normal.X; cB.Y = pointB.Y - radiusB * normal.Y;
                        points[0].X = 0.5f * (cA.X + cB.X); points[0].Y = 0.5f * (cA.Y + cB.Y);
#endif
		            }
		            break;

	            case ManifoldType.e_faceA:
		            {
#if !OPTIMIZE
			            normal = Math.Mul(xfA.R, manifold.localNormal);
			            Vector2 planePoint = Math.Mul(xfA, manifold.localPoint);

			            for (Int32 i = 0; i < manifold.pointCount; ++i)
			            {
				            Vector2 clipPoint = Math.Mul(xfB, manifold.points[i].localPoint);
				            Vector2 cA = clipPoint + (radiusA - Vector2.Dot(clipPoint - planePoint, normal)) * normal;
				            Vector2 cB = clipPoint - radiusB * normal;
				            points[i] = 0.5f * (cA + cB);
			            }
#else
                        Vector2 planePoint, clipPoint, cA, cB, t, t2, mpi;
                        float t3, t4;

                        normal.X = xfA.R.col1.X * manifold.localNormal.X + xfA.R.col2.X * manifold.localNormal.Y;
                        normal.Y = xfA.R.col1.Y * manifold.localNormal.X + xfA.R.col2.Y * manifold.localNormal.Y;

                        t.X = xfA.R.col1.X * manifold.localPoint.X + xfA.R.col2.X * manifold.localPoint.Y; t.Y = xfA.R.col1.Y * manifold.localPoint.X + xfA.R.col2.Y * manifold.localPoint.Y;
                        planePoint.X = xfA.position.X + t.X;
                        planePoint.Y = xfA.position.Y + t.Y;

                        for (Int32 i = 0; i < manifold.pointCount; ++i)
                        {
                            mpi = manifold.points[i].localPoint;
                            t.X = xfB.R.col1.X * mpi.X + xfB.R.col2.X * mpi.Y; t.Y = xfB.R.col1.Y * mpi.X + xfB.R.col2.Y * mpi.Y;
                            clipPoint.X = xfB.position.X + t.X;
                            clipPoint.Y = xfB.position.Y + t.Y;
                            t2.X = clipPoint.X - planePoint.X; t2.Y = clipPoint.Y - planePoint.Y;
                            t3 = t2.X * normal.X + t2.Y * normal.Y;
                            t4 = radiusA - t3;
                            cA.X = clipPoint.X + t4 * normal.X;
                            cA.Y = clipPoint.Y + t4 * normal.Y;
                            cB.X = clipPoint.X - radiusB * normal.X;
                            cB.Y = clipPoint.Y - radiusB * normal.Y;
                            points[i].X = 0.5f * (cA.X + cB.X);
                            points[i].Y = 0.5f * (cA.Y + cB.Y);
                        }

#endif
		            }
		            break;

	            case ManifoldType.e_faceB:
		            {
#if !OPTIMIZE
                        normal = Math.Mul(xfB.R, manifold.localNormal);
			            Vector2 planePoint = Math.Mul(xfB, manifold.localPoint);

			            for (Int32 i = 0; i < manifold.pointCount; ++i)
			            {
				            Vector2 clipPoint = Math.Mul(xfA, manifold.points[i].localPoint);
				            Vector2 cA = clipPoint - radiusA * normal;
				            Vector2 cB = clipPoint + (radiusB - Vector2.Dot(clipPoint - planePoint, normal)) * normal;
				            points[i] = 0.5f * (cA + cB);
			            }
#else
                        Vector2 planePoint, clipPoint, cA, cB, t, t2, mpi;
                        float t3, t4;

                        normal.X = xfB.R.col1.X * manifold.localNormal.X + xfB.R.col2.X * manifold.localNormal.Y;
                        normal.Y = xfB.R.col1.Y * manifold.localNormal.X + xfB.R.col2.Y * manifold.localNormal.Y;

                        t.X = xfB.R.col1.X * manifold.localPoint.X + xfB.R.col2.X * manifold.localPoint.Y; t.Y = xfB.R.col1.Y * manifold.localPoint.X + xfB.R.col2.Y * manifold.localPoint.Y;
                        planePoint.X = xfB.position.X + t.X;
                        planePoint.Y = xfB.position.Y + t.Y;

                        for (Int32 i = 0; i < manifold.pointCount; ++i)
                        {
                            mpi = manifold.points[i].localPoint;
                            t.X = xfA.R.col1.X * mpi.X + xfA.R.col2.X * mpi.Y; t.Y = xfA.R.col1.Y * mpi.X + xfA.R.col2.Y * mpi.Y;
                            clipPoint.X = xfA.position.X + t.X;
                            clipPoint.Y = xfA.position.Y + t.Y;
                            cA.X = clipPoint.X - radiusA * normal.X;
                            cA.Y = clipPoint.Y - radiusA * normal.Y;
                            t2.X = clipPoint.X - planePoint.X; t2.Y = clipPoint.Y - planePoint.Y;
                            t3 = t2.X * normal.X + t2.Y * normal.Y; // Vector2.Dot(t2, normal)
                            t4 = (radiusB - t3);
                            cB.X = clipPoint.X + t4 * normal.X;
                            cB.Y = clipPoint.Y + t4 * normal.Y;
                            points[i].X = 0.5f * (cA.X + cB.X);
                            points[i].Y = 0.5f * (cA.Y + cB.Y);
                        }
#endif
                        // Ensure normal points from A to B.
                        normal = -normal;
		            }
		            break;
	        }
        }

	    public Vector2 normal;						                                //< world vector pointing from A to B
        public Vector2[] points = new Vector2[PhysicSettings.MaxManifoldPoints];	//< world contact point (point of intersection)
    };

    /// <summary>This is used for determining the state of contact points.</summary>
    public enum PointState
    {
	    NullState,		/// point does not exist
	    AddState,		/// point was added in the update
	    PersistState,	/// point persisted across the update
	    RemoveState		/// point was removed in the update
    };

    /// <summary>Used for computing contact manifolds.</summary>
    public struct ClipVertex
    {
	    public Vector2 v;
	    public ContactID id;
    };

    /// <summary>Ray-cast input data. The ray extends from p1 to 
    /// p1 + maxFraction * (p2 - p1).
    /// </summary>
    public struct RayCastInput
    {
        public Vector2 p1, p2;
        public float maxFraction;
    };

    /// <summary>Ray-cast output data. The ray hits at
    /// p1 + fraction * (p2 - p1), where p1 and p2 come from RayCastInput.
    /// </summary>
    public struct RayCastOutput
    {
        public Vector2 normal;
        public float fraction;
    };

    /// <summary>An axis aligned bounding box.</summary>
#if !XBOX360 && !ZUNE
    [DebuggerDisplay("lowerBound: {lowerBound} upperBound: {upperBound}")]
#endif
    public struct AABB
    {
        public static AABB Empty = new AABB();

        public AABB(Vector2 lowerBound, Vector2 upperBound)
        {
            this.lowerBound = lowerBound;
            this.upperBound = upperBound;
        }

        /// <summary>Verify that the bounds are sorted.</summary>
        public bool IsValid()
        {
            Vector2 d = upperBound - lowerBound;
            bool valid = d.X >= 0.0f && d.Y >= 0.0f;
            valid = valid && (!(float.IsNaN(lowerBound.X) || float.IsNegativeInfinity(lowerBound.X) || float.IsPositiveInfinity(lowerBound.X)) &&
                               !(float.IsNaN(lowerBound.Y) || float.IsNegativeInfinity(lowerBound.Y) || float.IsPositiveInfinity(lowerBound.Y)) &&
                               !(float.IsNaN(upperBound.X) || float.IsNegativeInfinity(upperBound.X) || float.IsPositiveInfinity(upperBound.X)) &&
                               !(float.IsNaN(upperBound.Y) || float.IsNegativeInfinity(upperBound.Y) || float.IsPositiveInfinity(upperBound.Y)));
            return valid;
        }

        /// <summary>Get the center of the AABB.</summary>
	    public Vector2 GetCenter()
	    {
		    return 0.5f * (lowerBound + upperBound);
	    }

        /// <summary>Get the extents of the AABB (half-widths).</summary>
	    public Vector2 GetExtents()
	    {
		    return 0.5f * (upperBound - lowerBound);
	    }

        /// <summary>
        /// Get the perimeter length
        /// </summary>
        public float GetPerimeter()
        {
            float wx = upperBound.X - lowerBound.X;
            float wy = upperBound.Y - lowerBound.Y;
            return 2.0f * (wx + wy);
        }

        /// <summary>
        /// Combine an AABB into this one.
        /// </summary>
        /// <param name="aabb"></param>
        public void Combine(ref AABB aabb)
        {
            lowerBound = Vector2.Min(lowerBound, aabb.lowerBound);
            upperBound = Vector2.Max(upperBound, aabb.upperBound);
        }

        /// <summary>Combine two AABBs into this one.</summary>
	    public void Combine(ref AABB aabb1, ref AABB aabb2)
	    {
		    lowerBound = Vector2.Min(aabb1.lowerBound, aabb2.lowerBound);
		    upperBound = Vector2.Max(aabb1.upperBound, aabb2.upperBound);
	    }

        /// <summary>Does this aabb contain the provided AABB.</summary>
	    public bool Contains(ref AABB aabb)
	    {
		    bool result = true;
		    result = result && lowerBound.X <= aabb.lowerBound.X;
		    result = result && lowerBound.Y <= aabb.lowerBound.Y;
		    result = result && aabb.upperBound.X <= upperBound.X;
		    result = result && aabb.upperBound.Y <= upperBound.Y;
		    return result;
	    }

        /// <summary>
        /// Does this aabb contain the provided point.
        /// </summary>
        /// <param name="point"></param>
        /// <returns></returns>
        public bool Contains(ref Vector2 point)
        {
            bool result = true;
            result = result && lowerBound.X <= point.X;
            result = result && lowerBound.Y <= point.Y;
            result = result && point.X <= upperBound.X;
            result = result && point.Y <= upperBound.Y;
            return result;
        }

        // From Real-time Collision Detection, p179.
        public bool RayCast(out RayCastOutput output, ref RayCastInput input)
        {
            output = new RayCastOutput();

	        float tmin = -float.MaxValue;
	        float tmax = float.MaxValue;

	        Vector2 p = input.p1;
	        Vector2 d = input.p2 - input.p1;
	        Vector2 absD = Vector2Extensions.Abs(d);

	        Vector2 normal = Vector2.Zero;

	        for (Int32 i = 0; i < 2; ++i)
	        {
		        if (absD.Item(i) < PhysicSettings.FLT_EPSILON)
		        {
			        // Parallel.
			        if (p.Item(i) < lowerBound.Item(i) || upperBound.Item(i) < p.Item(i))
			        {
				        return false;
			        }
		        }
		        else
		        {
			        float inv_d = 1.0f / d.Item(i);
			        float t1 = (lowerBound.Item(i) - p.Item(i)) * inv_d;
			        float t2 = (upperBound.Item(i) - p.Item(i)) * inv_d;

			        // Sign of the normal vector.
			        float s = -1.0f;

			        if (t1 > t2)
			        {
				        Functions.Swap(ref t1, ref t2);
				        s = 1.0f;
			        }

			        // Push the min up
			        if (t1 > tmin)
			        {
				        normal = Vector2.Zero;
				        normal.Item(i,s);
				        tmin = t1;
			        }

			        // Pull the max down
			        tmax = MathHelper.Min(tmax, t2);

			        if (tmin > tmax)
			        {
				        return false;
			        }
		        }
	        }

	        // Does the ray start inside the box?
	        // Does the ray intersect beyond the max fraction?
	        if (tmin < 0.0f || input.maxFraction < tmin)
	        {
		        return false;
	        }

	        // Intersection.
	        output.fraction = tmin;
	        output.normal = normal;
	        return true;
        }

	    public Vector2 lowerBound;	///< the lower vertex
	    public Vector2 upperBound;	///< the upper vertex
    }

    public partial class Collision
    {
        // Sutherland-Hodgman clipping.
        internal static int ClipSegmentToLine(out ClipVertex[] vOut, ref ClipVertex[] vIn,
						                      ref Vector2 normal, ref float offset, ref int vertexIndexA)
        {
            vOut = new ClipVertex[2];

	        // Start with no output points
	        int numOut = 0;

	        // Calculate the distance of end points to the line
#if !OPTIMIZE
            float distance0 = Vector2.Dot(normal, vIn[0].v) - offset;
	        float distance1 = Vector2.Dot(normal, vIn[1].v) - offset;
#else
            float distance0; Vector2.Dot(ref normal, ref vIn[0].v, out distance0); distance0 = distance0 - offset;
            float distance1; Vector2.Dot(ref normal, ref vIn[1].v, out distance1); distance1 = distance1 - offset;
#endif

	        // If the points are behind the plane
	        if (distance0 <= 0.0f) vOut[numOut++] = vIn[0];
	        if (distance1 <= 0.0f) vOut[numOut++] = vIn[1];

	        // If the points are on different sides of the plane
	        if (distance0 * distance1 < 0.0f)
	        {
		        // Find intersection point of edge and plane
		        float interp = distance0 / (distance0 - distance1);
#if !OPTIMIZE
                vOut[numOut].v = vIn[0].v + interp * (vIn[1].v - vIn[0].v);
#else
                vOut[numOut].v.X = vIn[0].v.X + interp * (vIn[1].v.X - vIn[0].v.X);
                vOut[numOut].v.Y = vIn[0].v.Y + interp * (vIn[1].v.Y - vIn[0].v.Y);
#endif
		        
                // VertexA is hitting edgeB.
                vOut[numOut].id.cf.indexA = (byte)vertexIndexA;
                vOut[numOut].id.cf.indexB = vIn[0].id.cf.indexB;
                vOut[numOut].id.cf.typeA = ContactFeature.Type.VERTEX;
                vOut[numOut].id.cf.typeB = ContactFeature.Type.FACE;
                ++numOut;
	        }

	        return numOut;
        }

        public static bool TestOverlap(Shape shapeA, int indexA, 
                                          Shape shapeB, int indexB, 
                                          Transform xfA, Transform xfB)
        {
            DistanceInput input = new DistanceInput();
            input.proxyA.Set(shapeA, indexA);
            input.proxyB.Set(shapeB, indexB);
            input.transformA = xfA;
            input.transformB = xfB;
            input.useRadii = true;

            SimplexCache cache = new SimplexCache();
            cache.count = 0;

            DistanceOutput output;

            Distance(out output, ref cache, ref input);

            return output.distance < 10.0f * PhysicSettings.FLT_EPSILON;
        }

        public static void GetPointStates(PointState[] state1, PointState[] state2,
					                        Manifold manifold1, Manifold manifold2)
        {
	        for (int i = 0; i < PhysicSettings.MaxManifoldPoints; ++i)
	        {
		        state1[i] = PointState.NullState;
                state2[i] = PointState.NullState;
	        }

	        // Detect persists and removes.
	        for (Int32 i = 0; i < manifold1.pointCount; ++i)
	        {
		        ContactID id = manifold1.points[i].id;

		        state1[i] = PointState.RemoveState;

		        for (Int32 j = 0; j < manifold2.pointCount; ++j)
		        {
			        if (manifold2.points[j].id.key == id.key)
			        {
				        state1[i] = PointState.PersistState;
				        break;
			        }
		        }
	        }

	        // Detect persists and adds.
	        for (Int32 i = 0; i < manifold2.pointCount; ++i)
	        {
		        ContactID id = manifold2.points[i].id;

		        state2[i] = PointState.AddState;

		        for (Int32 j = 0; j < manifold1.pointCount; ++j)
		        {
			        if (manifold1.points[j].id.key == id.key)
			        {
				        state2[i] = PointState.PersistState;
				        break;
			        }
		        }
	        }
        }

        public static bool TestOverlap(ref AABB a, ref AABB b)
        {
            Vector2 d1, d2;
            d1 = b.lowerBound - a.upperBound;
            d2 = a.lowerBound - b.upperBound;

            if (d1.X > 0.0f || d1.Y > 0.0f)
                return false;

            if (d2.X > 0.0f || d2.Y > 0.0f)
                return false;

            return true;
        }
    }
}
